home *** CD-ROM | disk | FTP | other *** search
- ##############################################################################
- #
- # Zope Public License (ZPL) Version 1.0
- # -------------------------------------
- #
- # Copyright (c) Digital Creations. All rights reserved.
- #
- # This license has been certified as Open Source(tm).
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions are
- # met:
- #
- # 1. Redistributions in source code must retain the above copyright
- # notice, this list of conditions, and the following disclaimer.
- #
- # 2. Redistributions in binary form must reproduce the above copyright
- # notice, this list of conditions, and the following disclaimer in
- # the documentation and/or other materials provided with the
- # distribution.
- #
- # 3. Digital Creations requests that attribution be given to Zope
- # in any manner possible. Zope includes a "Powered by Zope"
- # button that is installed by default. While it is not a license
- # violation to remove this button, it is requested that the
- # attribution remain. A significant investment has been put
- # into Zope, and this effort will continue if the Zope community
- # continues to grow. This is one way to assure that growth.
- #
- # 4. All advertising materials and documentation mentioning
- # features derived from or use of this software must display
- # the following acknowledgement:
- #
- # "This product includes software developed by Digital Creations
- # for use in the Z Object Publishing Environment
- # (http://www.zope.org/)."
- #
- # In the event that the product being advertised includes an
- # intact Zope distribution (with copyright and license included)
- # then this clause is waived.
- #
- # 5. Names associated with Zope or Digital Creations must not be used to
- # endorse or promote products derived from this software without
- # prior written permission from Digital Creations.
- #
- # 6. Modified redistributions of any form whatsoever must retain
- # the following acknowledgment:
- #
- # "This product includes software developed by Digital Creations
- # for use in the Z Object Publishing Environment
- # (http://www.zope.org/)."
- #
- # Intact (re-)distributions of any official Zope release do not
- # require an external acknowledgement.
- #
- # 7. Modifications are encouraged but must be packaged separately as
- # patches to official Zope releases. Distributions that do not
- # clearly separate the patches from the original work must be clearly
- # labeled as unofficial distributions. Modifications which do not
- # carry the name Zope may be packaged in any form, as long as they
- # conform to all of the clauses above.
- #
- #
- # Disclaimer
- #
- # THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
- # EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
- # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- # SUCH DAMAGE.
- #
- #
- # This software consists of contributions made by Digital Creations and
- # many individuals on behalf of Digital Creations. Specific
- # attributions are listed in the accompanying credits file.
- #
- ##############################################################################
- """Read and (re-)format BoboPOS 2 database files
- """
-
- import struct, string, sys, time, os
-
- try: from cStringIO import StringIO
- except: from StringIO import StringIO
-
- ppml=None
-
- file__version__=3.0
- packed_version='SDBMV'+struct.pack(">f",file__version__)
-
- def error(message, fatal=0, exc=0):
- if exc:
- sys.stderr.write('%s: %s' % (sys.exc_info()[0], sys.exc_info()[1]))
- sys.stderr.write("\n%s\n" % message)
- if fatal: sys.exit(fatal)
-
- def _read_and_report(file, rpt=None, fromEnd=0, both=0, n=99999999, show=0,
- forgive=0, export=0):
- """\
- Read a file's index up to the given time.
- """
- first=1
- seek=file.seek
- read=file.read
- unpack=struct.unpack
- split=string.split
- join=string.join
- find=string.find
- seek(0,2)
- file_size=file.tell()
- if not export:
- seek(0)
- h=read(len(packed_version))
- if h != packed_version:
- if h[:4]=='FS21':
- error("The input file is a ZODB File Storage\n"
- "This script only works with ZODB 2 (BoboPOS) "
- "data or export files."
- ,1)
- else:
- error("The input file is not a ZODB 2 database file.\n"
- "This script only works with ZODB 2 (BoboPOS) "
- "data or export files."
- ,1)
-
- gmtime=time.gmtime
-
- if fromEnd: pos=file_size
- else: pos=newpos=(not export) and len(packed_version)
-
- tlast=0
- err=0
- tnamelast=None
- while 1:
- if fromEnd:
- seek(pos-4)
- l=unpack(">i", read(4))[0]
- if l==0:
- b=pos
- p=pos-4
- while l==0:
- p=p-4
- seek(p)
- l=unpack(">i", read(4))[0]
-
- pos=p+4
- error("nulls skipped from %s to %s" % (pos,b))
- p=pos-l
- if p < 0:
- error('Corrupted data before %s' % pos)
- if show > 0:
- p=pos-show
- if p < 0: p=0
- seek(p)
- p=read(pos-p)
- else:
- p=''
- error(p,1)
- pos=p
- else:
- pos=newpos
-
- seek(pos)
- h=read(24) # 24=header_size
- if not h: break
- if len(h) != 24: break
- oid,prev,start,tlen,plen=unpack(">iidii",h)
-
- if prev < 0 or (prev and (prev >= pos)):
- error('Bad previous record pointer (%s) at %s' % (prev, pos))
- if show > 0: error(read(show))
- if not forgive:
- err=1
- break
-
- if start < tlast:
- error('record time stamps are not chronological at %s' % pos)
- if show > 0: error(read(show))
- if not forgive:
- err=1
- break
-
- if plen > tlen or plen < 0 or oid < -999:
- error('Corrupted data record at %s' % pos)
- if show > 0: error(read(show))
- err=1
- break
-
-
- newpos=pos+tlen
- if newpos > file_size:
- error('Truncated data record at %s' % pos)
- if show > 0: error(read(show))
- if not forgive:
- err=1
- break
-
- seek(newpos-4)
- if read(4) != h[16:20]:
- __traceback_info__=pos, oid,prev,start,tlen,plen
- error('Corrupted data record at %s' % pos)
- if show > 0:
- seek(pos+24)
- error(read(show))
- err=1
- break
-
- tlast=start-100
-
- if rpt is None: continue
- n=n-1
- if n < 1: break
-
- seek(pos+24)
- if plen > 0:
- p=read(plen)
- if p[-1:] != '.':
- error('Corrupted pickle at %s %s %s' % (pos,plen,len(p)))
- if show > 0:
- seek(pos+24)
- error(read(show))
- err=1
- break
-
- else: p=''
- t=split(read(tlen-plen-28),'\t')
- tname, user = (t+[''])[:2]
- t=join(t[2:],'\t')
- start,f=divmod(start,1)
- y,m,d,h,mn,s=gmtime(start)[:6]
- s=s+f
- start="%.4d-%.2d-%.2d %.2d:%.2d:%.3f" % (y,m,d,h,mn,s)
- rpt(pos,oid,start,tname,user,t,p,first,tname!=tnamelast)
- first=0
- tnamelast=tname
-
- if err and both and not fromEnd:
- _read_and_report(file, rpt, 1, 0, n, show)
-
- rpt(None, None, None, None, None, None, None, None, None)
-
-
- def none(*ignored): pass
-
- def positions(pos, *ignored):
- if pos is not None: sys.stdout.write("%s\n" % pos)
-
- def oids(pos, oid, *ignored):
- if pos is not None: sys.stdout.write("%s\n" % oid)
-
- def tab_delimited(*args):
- sys.stdout.write("%s\n" % string.join(args[:6],'\t'))
-
- def undo_log(pos, oid, start, tname, user, t, p, first, newtrans):
- if not newtrans: return
-
- sys.stdout.write("%s:\t%s\t%s\t%s\n" % (pos, start, user, t))
-
-
- reports={
- 'none': (none,
- ('Read a database file checking for errors',
- 'but producing no output')
- ),
- 'oids': (oids,
- ('Read the database and output object ids',)),
- 'positions': (positions,
- ('Read the database and output record positions',)),
- 'tab_delimited': (tab_delimited,
- ('Output record meta-data in tab-delimited format',)),
-
- 'undo': (undo_log,
- (
- 'Output a transaction summary that shows the position of',
- 'each transaction. This is useful for undoing ',
- 'transactions from the OS command line when',
- 'some programming error has caused objects to get to',
- 'a state where Zope can\'t start up.',
- '',
- 'Eventually, there will be an undo utility for undoing',
- 'individual transactions. For now, you can simply',
- 'truncate the file at the position of a problem',
- 'transaction to return the database to the state it',
- 'was in before the transaction',
- )),
- }
-
- def main(argv):
- import getopt
-
- items=reports.items()
- items.sort()
-
- usage="""Usage: python %s [options] filename
-
- where filename is the name of the database file.
-
- options:
-
- -r report
-
- Specify an output report.
-
- The valid reports are:\n\n\t\t%s
-
- -e
-
- Read the file from back to front
-
- -l n
-
- Show only n records
-
- -b
-
- If an error is encountered while reading from front,
- ret reading from the back.
-
- -s n
-
- If a corrupted data record is found, show the first n
- bytes of the corrupted record.
-
- -f filename
-
- Convert to ZODB 3 File-Storage format
-
- -p path
-
- Add a directory to the Python path.
-
- -x
-
- The input file is a ZODB 2 export file.
-
-
- """ % (sys.argv[0],
- string.join(map(
- lambda i:
- ("%s --\n\t\t\t%s" % (i[0], string.join(i[1][1],'\n\t\t\t'))),
- items),
- ',\n\n\t\t'))
-
- sys.path.append(os.path.split(sys.argv[0])[0])
-
- try:
- opts, args = getopt.getopt(argv,'r:ebl:s:f:p:x')
- filename,=args
- except: error(usage,1,1)
-
- try: file=open(filename,'rb')
- except: error('Coud not open %s' % filename,1,1)
-
- rpt=none
- fromEnd=0
- both=0
- n=99999999
- show=0
- export=0
- convert=0
- for o, v in opts:
- o=o[1:]
- if o=='r':
- try: rpt=reports[v][0]
- except: error('Invalid report: %s' % v, 1)
- elif o=='l':
- try: n=string.atoi(v)
- except: error('The number of records, %s, shuld ne an integer'
- % v, 1)
- elif o=='s':
- try: show=string.atoi(v)
- except: error('The number of bytes, %s, shuld ne an integer'
- % v, 1)
- elif o=='e': fromEnd=1
- elif o=='x': export=1
- elif o=='f': convert=1
- elif o=='b': both=1
- elif o=='p':
- if v=='-':
- v=os.path.join(
- os.path.split(sys.argv[0])[0],
- '..','lib','python')
- sys.path.insert(0,v)
- print sys.path
- else: error('Unrecognized option: -%s' % o, 1)
-
- if convert:
- import FS
- if export:
- rpt=FS.ZEXP(v, file).rpt
- else:
- rpt=FS.FS(v, file).rpt
-
- _read_and_report(file, rpt, fromEnd, both, n, show,
- forgive=1, export=export)
-
- if __name__=='__main__': main(sys.argv[1:])
-